package com.gnerv.rabbitmq.agent.handler.v_3_7;

import com.gnerv.rabbitmq.agent.handler.AbstractStatusExecResultHandler;
import com.gnerv.rabbitmq.agent.model.entity.NodeStatus;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StringUtils;

import java.util.Map;
import java.util.regex.Pattern;

/**
 * @author Gnerv LiGen
 */
@Slf4j
public class StatusExecResultHandler extends AbstractStatusExecResultHandler {

    private static final Pattern NODE_NAME = Pattern.compile("Status of node (\\S*) ...");
    private static final Pattern VERSION = Pattern.compile("\\{rabbit\\,\\\"RabbitMQ\\\"\\,\\\"(\\S*)\"}");
    private static final Pattern FILE_DESCRIPTORS_TOTAL_LIMIT = Pattern.compile("\\{total_limit\\,(\\w*)\\}");
    private static final Pattern FILE_DESCRIPTORS_TOTAL_USED = Pattern.compile("\\{total_used\\,(\\w*)\\}");
    private static final Pattern SOCKETS_LIMIT = Pattern.compile("\\{sockets_limit\\,(\\w*)\\}");
    private static final Pattern SOCKETS_USED = Pattern.compile("\\{sockets_used\\,(\\w*)\\}");
    private static final Pattern PROCESSES = Pattern.compile("\\{processes\\,\\[\\{limit\\,(\\w*)\\}\\,\\{used\\,(\\w*)\\}\\]\\}");
    private static final Pattern DISK_FREE = Pattern.compile("\\{disk_free\\,(\\w*)\\}");
    private static final Pattern DISK_FREE_LIMIT = Pattern.compile("\\{disk_free_limit\\,(\\w*)\\}");
    private static final Pattern MEMORY_USED = Pattern.compile("\\{rss\\,(\\w*)\\}\\,\\{allocated\\,(\\w*)\\}");
    private static final Pattern MEMORY_LIMIT = Pattern.compile("\\{vm_memory_limit\\,(\\w*)\\}");
    private static final Pattern MEMORY_HIGH_WATERMARK = Pattern.compile("\\{vm_memory_high_watermark\\,(\\S*)\\}");
    private static final Pattern MEMORY_CALCULATION_STRATEGY = Pattern.compile("\\{vm_memory_calculation_strategy\\,(\\S*)\\}");
    private static final Pattern OS = Pattern.compile("\\{os\\,\\{(\\S*)\\,(\\S*)\\}\\}");
    private static final Pattern ERLANG_VERSION = Pattern.compile("Erlang\\/OTP (\\w*) \\[");
    private static final Pattern LISTENER_AMQP = Pattern.compile("\\{amqp\\,(\\w*)\\,\\\"\\:\\:\\\"\\}");
    private static final Pattern LISTENER_HTTP = Pattern.compile("\\{http\\,(\\w*)\\,\\\"\\:\\:\\\"\\}");
    private static final Pattern UPTIME = Pattern.compile("\\{uptime\\,(\\w*)\\}");

    protected void type() {
        nodeStatus.setType("disc");
    }

    @Override
    protected void status() {
        nodeStatus.setType("running");
    }

    @Override
    protected void fileDescriptors() {
        Map<Integer, String> matcher = matcher(FILE_DESCRIPTORS_TOTAL_LIMIT, 1);
        String limit = matcher.get(1);
        nodeStatus.getFileDescriptor().setLimit(Long.parseLong(limit));
        matcher = matcher(FILE_DESCRIPTORS_TOTAL_USED, 1);
        String used = matcher.get(1);
        nodeStatus.getFileDescriptor().setUsed(Long.parseLong(used));
    }

    @Override
    protected void sockets() {
        Map<Integer, String> matcher = matcher(SOCKETS_LIMIT, 1);
        String limit = matcher.get(1);
        nodeStatus.getSocketDescriptor().setLimit(Long.parseLong(limit));
        matcher = matcher(SOCKETS_USED, 1);
        String used = matcher.get(1);
        nodeStatus.getSocketDescriptor().setUsed(Long.parseLong(used));
    }

    @Override
    protected void processes() {
        Map<Integer, String> matcher = matcher(PROCESSES, 1, 2);
        String limit = matcher.get(1);
        nodeStatus.getErlangProcesses().setLimit(Long.parseLong(limit));
        String used = matcher.get(2);
        nodeStatus.getErlangProcesses().setUsed(Long.parseLong(used));
    }

    @Override
    protected void diskFree() {
        Map<Integer, String> matcher = matcher(DISK_FREE, 1);
        String diskFree = matcher.get(1);
        nodeStatus.getDisk().setLimit(Long.parseLong(diskFree));
    }

    @Override
    protected void diskFreeLimit() {
        Map<Integer, String> matcher = matcher(DISK_FREE_LIMIT, 1);
        String diskFreeLimit = matcher.get(1);
        nodeStatus.getDisk().setLimit(Long.parseLong(diskFreeLimit));
    }

    @Override
    protected void memoryUsed() {
        Map<Integer, String> matcher = matcher(MEMORY_USED, 1, 2);
        String rss = matcher.get(1);
        long used = Long.parseLong(rss);
        String allocated = matcher.get(2);
        used = used + Long.parseLong(allocated);
        nodeStatus.getMemory().setUsed(used);
    }

    @Override
    protected void memoryLimit() {
        Map<Integer, String> matcher = matcher(MEMORY_LIMIT, 1);
        String memoryLimit = matcher.get(1);
        nodeStatus.getMemory().setLimit(Long.parseLong(memoryLimit));
    }

    @Override
    protected void memoryHighWatermark() {
        Map<Integer, String> matcher = matcher(MEMORY_HIGH_WATERMARK, 1);
        String memoryHighWatermark = matcher.get(1);
        nodeStatus.setMemoryHighWatermark(memoryHighWatermark);
    }

    @Override
    protected void memoryCalculationStrategy() {
        Map<Integer, String> matcher = matcher(MEMORY_CALCULATION_STRATEGY, 1);
        String memoryCalculationStrategy = matcher.get(1);
        nodeStatus.setMemoryCalculationStrategy(memoryCalculationStrategy);
    }

    @Override
    protected void os() {
        Map<Integer, String> matcher = matcher(OS, 1, 2);
        String os = matcher.values().toString();
        nodeStatus.setOs(os);
    }

    @Override
    protected void erlangVersion() {
        Map<Integer, String> matcher = matcher(ERLANG_VERSION, 1);
        String erlangVersion = "Erlang/OTP " + matcher.get(1);
        nodeStatus.setErlangVersion(erlangVersion);
    }

    @Override
    protected void listeners() {
        Map<Integer, String> matcher = matcher(LISTENER_AMQP, 1);
        String amqp = matcher.get(1);
        if (StringUtils.hasText(amqp)) {
            nodeStatus.getListeners().add(new NodeStatus.Listener("amqp", "::", Integer.parseInt(amqp)));
        }
        matcher = matcher(LISTENER_HTTP, 1);
        String http = matcher.get(1);
        if (StringUtils.hasText(http)) {
            nodeStatus.getListeners().add(new NodeStatus.Listener("http", "::", Integer.parseInt(http)));
        }
    }

    @Override
    protected void uptime() {
        Map<Integer, String> matcher = matcher(UPTIME, 1);
        String uptime = matcher.get(1);
        nodeStatus.setUptime(Long.parseLong(uptime));
    }

    protected void nodeName() {
        Map<Integer, String> matcher = matcher(NODE_NAME, 1);
        String nodeName = matcher.get(1);
        nodeStatus.setName(nodeName);
    }

    protected void version() {
        Map<Integer, String> matcher = matcher(VERSION, 1);
        String version = matcher.get(1);
        nodeStatus.setVersion(version);
    }

}
